#!/usr/bin/php
<?php
/* 
 * Script to download multiple videos from youtube (using youtube-dl [1]), convert into
 * AVI (same size and framerate), then merge together
 *
 * how to setup:
 * sudo wget -o /usr/bin/youtube-multi http://svn.phpntips.com/projects/youtube-merge/youtube-multi
 * sudo wget -o /usr/bin/youtube-dl https://github.com/rg3/youtube-dl/raw/2010.12.09/youtube-dl
 *
 * version 10/01/2011
 *
 * How to use:
 * pass the urls as parameters to this file using Command line
 *
 * e.g.
 * youtube-multi "http://www.youtube.com/watch?v=MaZRgTJlN2Y&NR=1" "http://www.youtube.com/watch?v=na_3XoysbCk"
 *
 *
 * Requirements:
 *  [1] youtube-dl [https://github.com/rg3/youtube-dl/raw/2010.12.09/youtube-dl]
 *      download it in this path or elsewhere and configure constants below
 *  [2] mencoder
 *  [3] php 5.3 CLI
 *  [4] python for youtube-dl
 *
 * @copyright Elvis Ciotti - phpntips.com
 * @licence new BSD
 *
*/

define('MAX_THREADS', 5);
define('YOUTUBE_DL', /*'./'.*/'youtube-dl');
define('LOGFILE', '/tmp/convert.php.log');
define('NO_CONVERT', '-nc');
define('NO_MERGE'  , '-nm');
/*define('CMDLINE_ENCODER', '-ovc lavc -lavcopts vcodec=mpeg4:vbitrate=1500:mbd=2:v4mv:autoaspect '
  . ' -ofps 25 -vf pp=lb '
  . ' -oac mp3lame -lameopts fast:preset=standard '
  . ' -vf scale=640:480 -o'
);*/
define('CMDLINE_ENCODER', '-ovc xvid -xvidencopts bitrate=3000:pass=1'
  . ' -ofps 25 ' #-vf pp=lb 
  . ' -oac mp3lame -lameopts cbr:mode=2:br=128 -af resample=44100 -srate 44100'
  . ' -vf scale=640:480  ' #-ffourcc XVID
);



$outVideos = array();
$finalName = '';
$t = new Threads;
$t->maxThreads = MAX_THREADS;
$encode = true;
$merge = true;
foreach (array_slice($argv,1) as $arg) {
    $parts = @parse_url($arg);
    if (isset($parts['host'])) {
       // youtube download
       if (isset($parts['host']) && $parts['host']=='www.youtube.com') {
         parse_str($parts['query'], $vars);
         $videoId = $vars['v'];
       } else {
         $videoId = time();
       }
       $flv = $encode ?  '_'.$videoId.'.flv.tmp'   :   $videoId.'.flv';
       $avi = '_'.$videoId.'.avi.tmp';
       if (!in_array($avi, $outVideos)) {
         $outVideos[] = $avi;	
         $finalName .= $videoId;

         $downloadCmd = '';
         if ($parts['host']=='www.youtube.com') {
              // download FLV via youtube-dl
              $downloadCmd = YOUTUBE_DL . ' -o "'.$flv.'" "'.$arg.'"';
         } else if (preg_match('#^http://.*.flv$#i', $arg)) {
	       // direct FVL download
	      $downloadCmd =  'wget -o "'.$flv.'" "'.$arg.'"';

	 } else /*if (preg_match('#^http://#i', $arg))*/ { 
	       //  search FVL inside the page
	       preg_match('#http:[^\"]+\.flv#i', file_get_contents($arg), $matches);
	       $flvLink = isset($matches[0]) ? $matches[0] : null;

	       if ($flvLink) {
            $downloadCmd =  'echo "wget '.$flv.'..."; wget -o "'.$flv.'" "'.$flvLink.'"';
	       }
	 }
         // CONVERT FLV 2 AVI 640x480 25fps
         $encodeCmd = $encode ? 'mencoder "'.$flv.'" '.CMDLINE_ENCODER .' -o "'.$avi.'"'
                              : '';
         $t->execAndLog($downloadCmd.';'.$encodeCmd);
       }


   }  else {
       $encode = $arg === NO_CONVERT ? false : $encode;
       $merge =  $arg === NO_MERGE ? false : $merge;
       $finalName = preg_replace("/[^a-z0-9-_]/i","",$arg);
       echo "param not url, skipped\n";
   }
}

if (empty($outVideos)) { exit("no video downloaded"); }
if ($merge) {
   $t->waitFinishing();
   echo "\n\n\n MERGING !!!\n\n\n";
   $t->execAndLog(
       "mencoder -ovc copy -oac copy "
       . implode(' ', $outVideos)." -o OUT_" 
       . $finalName."_".count($outVideos)."videos.avi"
   );
}

class Threads
{
	private $processes = array();
	public $maxThreads = 2;

	function log($cmd)
        {
	   $f = fopen(LOGFILE, 'a+');
	   fwrite($f, $cmd."\n");
	   fclose($f);
        }

	function execAndLog($cmd)
	{
           while ($this->countRunningProcesses() > $this->maxThreads) {
	      sleep(2);
           }
	   $this->log($cmd);
	   $ar = array();
	   $this->processes[] = proc_open($cmd,array(),$ar);

	}

	function waitFinishing()
	{
	  while ($this->countRunningProcesses()>0) {
	    sleep(2);
	  }
	}

       
	function countRunningProcesses()
	{
	   $ret = 0; 
	   foreach($this->processes as $process) {
	      $status = proc_get_status($process);
	      if ($status['running']) {
		 $ret++;
	      }
	   }
	   return $ret;
	}
}
